/**
 * <p>Title: liteflow</p>
 * <p>Description: 轻量级的组件式流程框架</p>
 *
 * @author Bryan.Zhang
 * @email weenyc31@163.com
 * @Date 2020/4/1
 */
package com.gonsin.ta.logic.spring;

import com.gonsin.ta.logic.annotations.NodeMethod;
import com.gonsin.ta.logic.annotations.NodeComponent;
import com.gonsin.ta.logic.enums.NodeTypeEnum;
import com.gonsin.ta.logic.components.RunNode;
import com.gonsin.ta.logic.components.SignalNode;
import com.gonsin.ta.logic.components.SwitchNode;
import com.gonsin.ta.logic.config.BaseTaConfig;
import com.gonsin.ta.logic.node.*;
import com.gonsin.ta.logic.process.TaBus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * 组件扫描类，只要是NodeComponent的实现类，都可以被这个扫描器扫到
 * @author Bryan.Zhang
 */
@Component
public class ComponentScanner implements BeanPostProcessor {

    private static final Logger LOG = LoggerFactory.getLogger(ComponentScanner.class);

    public static Map<String, Node> nodeComponentMap = new HashMap<>();
    public static Map<String, Node> nodeMethodMap = new HashMap<>();

    public static Map<String, Object> allComponents = new HashMap<>();

    private BaseTaConfig taConfig;

//    public static ICmpAroundAspect cmpAroundAspect;

    public ComponentScanner() {
    }

    public static Object getBean(String beanName) {
        return allComponents.get(beanName);
    }

    public static void putBean(String beanName, Object bean) {
        allComponents.put(beanName, bean);
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @SuppressWarnings("rawtypes")
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Class clazz = bean.getClass();
        allComponents.put(beanName, bean);

        //判断是不是声明式组件
        //如果是，就缓存到类属性的map中
        Method[] methods = clazz.getMethods();
        for(Method method : methods){
            NodeMethod nodeMethod = method.getDeclaredAnnotation(NodeMethod.class);
            if(nodeMethod == null){
                continue;
            }

            NodeTypeEnum nodeType = nodeMethod.type();
            String nodeId = nodeMethod.nodeId();
            NodeComponentProxy nodeComponent = NodeProxyUtil.method2NodeComponent(nodeId, nodeType, bean, beanName, method);
            switch(nodeType){
//                case RUN: TaBus.addNode(new RunNodeAdapter(nodeComponent), false); break;
                case RUN: nodeMethodMap.put(beanName + "@" + nodeId, new RunNodeAdapter(nodeComponent)); break;
//                case SWITCH: TaBus.addNode(new SwitchNodeAdapter(nodeComponent), false); break;
                case SWITCH: nodeMethodMap.put(beanName + "@" + nodeId, new SwitchNodeAdapter(nodeComponent)); break;
//                case SIGNAL: TaBus.addNode(new SignalNodeAdapter(nodeComponent), false); break;
                case SIGNAL: nodeMethodMap.put(beanName + "@" + nodeId, new SignalNodeAdapter(nodeComponent)); break;
            }
        }

        NodeComponent component = (NodeComponent) clazz.getDeclaredAnnotation(NodeComponent.class);
        if(component == null){
            return bean;
        }
        if(RunNode.class.isAssignableFrom(clazz)){
            NodeComponentProxy nodeComponent = NodeProxyUtil.bean2NodeComponent(component, NodeTypeEnum.RUN, bean, beanName);
//            TaBus.addNode(new RunNodeAdapter(nodeComponent), false);
            nodeComponentMap.put(beanName, new RunNodeAdapter(nodeComponent));
            return bean;
        }

        if(SwitchNode.class.isAssignableFrom(clazz)){
            NodeComponentProxy nodeComponent = NodeProxyUtil.bean2NodeComponent(component, NodeTypeEnum.SWITCH, bean, beanName);
//            TaBus.addNode(new SwitchNodeAdapter(nodeComponent), false);
            nodeComponentMap.put(beanName, new SwitchNodeAdapter(nodeComponent));
            return bean;
        }

        if(SignalNode.class.isAssignableFrom(clazz)){
            NodeComponentProxy nodeComponent = NodeProxyUtil.bean2NodeComponent(component, NodeTypeEnum.SIGNAL, bean, beanName);
//            TaBus.addNode(new SignalNodeAdapter(nodeComponent), false);
            nodeComponentMap.put(beanName, new SignalNodeAdapter(nodeComponent));
            return bean;
        }

        return bean;
    }

    //用于清楚spring上下文扫描到的组件实体
    public static void cleanCache() {
        nodeComponentMap.clear();
    }
}

